//
// Created by LiuYou on 2021/10/23.
//

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
#include <csignal>


static int srcFd;

static const int CPS = 1024;
//static volatile int tokens = 0;
/*
 * todo 笔记: An integral type that can be modified atomically, without the possibility of a signal arriving in the middle of the operation.
 *   一种可以原子方式修改的整数类型，在操作过程中不可能有信号到达。
 */
static volatile sig_atomic_t tokens = 0;
static const int BURST = 100;


static void releaseResources() {
    close( srcFd );

    const char str[] = "释放文件描述符。\n.";
    write( STDOUT_FILENO, str, sizeof( str ) - 1 );
}


void alarmHandler(int signal) {
    ++tokens;
    if (tokens > BURST) {
        tokens = BURST;
    }
    alarm( 1 );
}


int main(int argc, char** argv) {
    signal( SIGALRM, alarmHandler );
    alarm( 1 );


    srcFd = open( argv[1], O_RDONLY );
    atexit( releaseResources );


    /*
     * 定时循环。
     */
    char buffer[CPS]{};
    ssize_t readBytes{};

    // todo 笔记: 阻塞的系统调用会被信号打断。
    while ((readBytes = read( srcFd, buffer, sizeof( buffer ))) != 0) {
        if (readBytes < 0) {
            perror( "read()" );
            exit( 1 );
        }
        ssize_t writeBytes{};
        int writePos{};
        while ((writeBytes = write( STDOUT_FILENO, buffer + writePos, readBytes )) != readBytes) {
            writePos += static_cast<int>(writeBytes);
            readBytes -= writePos;
        }

        while (tokens <= 0) {
            pause();
        }
        --tokens;

    }


    return 0;
}
